﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using Fasterflect;
using Kugar.Core.ExtMethod;
using Kugar.Tools.SQLHelper.SQLGenerator.BllT4;
using Kugar.Tools.SQLHelper.SQLGenerator.EntityT4;
using Kugar.Tools.SQLHelper.SQLGenerator.ViewT4;
using Microsoft.Data.ConnectionUI;
using Newtonsoft.Json.Linq;
using MethodInvoker = System.Windows.Forms.MethodInvoker;

namespace Kugar.Tools.SQLHelper.SQLGenerator
{
    public partial class Generator : Form
    {

        public Generator()
        {
            InitializeComponent();
            
        }


        private SQLBuilder _builder = null;
        private void btnBuildConnStr_Click(object sender, EventArgs e)
        {
            using (DataConnectionDialog dlg = new DataConnectionDialog())
            {
                //添加数据源
                //dlg.DataSources.Add(DataSource.AccessDataSource);
                //dlg.DataSources.Add(DataSource.OdbcDataSource);
                //dlg.DataSources.Add(DataSource.OracleDataSource);
                dlg.DataSources.Add(DataSource.SqlDataSource);
                dlg.SetSelectedDataProvider(DataSource.SqlDataSource, DataProvider.SqlDataProvider);
                //dlg.DataSources.Add(DataSource.SqlFileDataSource);
                //设置默认数据提供对象
                dlg.SelectedDataSource = DataSource.SqlDataSource;
                dlg.SelectedDataProvider =DataProvider.SqlDataProvider;
                dlg.Text = "生成数据库连接字符串";
                //只能够通过DataConnectionDialog类的静态方琺Show出对话框
                //不同使用dialog.Show()或dialog.ShowDialog()来呈现对话框
                if (Microsoft.Data.ConnectionUI.DataConnectionDialog.Show(dlg) == System.Windows.Forms.DialogResult.OK)
                {
                    cmbConnStr.Text = dlg.ConnectionString;
                }
            }
        }

        
        private void btnFoderPicker_Click(object sender, EventArgs e)
        {
            getFolderPath(cmbEntityGeneratePath);
        }

        private void btnRefreshDb_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(cmbConnStr.Text))
            {
                MessageBox.Show("请先输入连接字符串");
                return;
            }

            

            if (!connToDB(cmbConnStr.Text))
            {
                MessageBox.Show("连接失败");
            }
        }

        private void btnGetDbStruct_Click(object sender, EventArgs e)
        {
            //ckTableList.Items.Clear();

            //if (!string.IsNullOrWhiteSpace(cmbDbList.SelectedItem.ToStringEx()))
            //{
            //    var tbllst = _builder.GetTables(cmbDbList.SelectedItem.ToStringEx());

            //    ckTableList.Items.AddRange(tbllst);

                
                
            //}

            refreshStruct();
        }

        private void ckTableList_SelectedValueChanged(object sender, EventArgs e)
        {
            var tbl = ckTableList.SelectedItem as DbTableStructInfo;

            if (tbl!=null)
            {
                dataGridView1.DataSource = tbl.Columns;

            }

        }

        private void loadConfigFromFile(string filePath)
        {
            if (File.Exists(filePath))
            {
                var config = JObject.Parse(File.ReadAllText(filePath, Encoding.UTF8));

                var entityJson = config.GetJObject("Entity");

                if (entityJson != null)
                {
                    cmbConnStr.Items.AddRange(entityJson.GetJArray("ConnStr").Select(x => (string)x).ToArrayEx());

                    if (cmbConnStr.Items.Count > 0)
                    {
                        //cmbConnStr.SelectedIndex = 0;
                    }

                    cmbEntityGeneratePath.Items.AddRange(entityJson.GetJArray("DescFolder").Select(x => (string)x).ToArrayEx());

                    if (cmbEntityGeneratePath.Items.Count > 0)
                    {
                        cmbEntityGeneratePath.SelectedIndex = 0;
                    }

                    txtNamespace.Text = entityJson.GetString("LastNamespace");
                }

                var bllJson = config.GetJObject("BLL");

                if (bllJson != null)
                {
                    txtBllName.Text = bllJson.GetString("BLLName");
                    txtBLLNamespace.Text = bllJson.GetString("LastNamespace");
                    cmbBLLGeneratePath.Items.AddRange(bllJson.GetJArray("DescFolder").Select(x => (string)x).ToArrayEx());

                    if (cmbBLLGeneratePath.Items.Count > 0)
                    {
                        cmbBLLGeneratePath.SelectedIndex = 0;
                    }
                }                
            }


        }

        private void saveConfigToFile()
        {
            if (!cmbEntityGeneratePath.Items.AsEnumerable<string>().Any(x=>x== cmbEntityGeneratePath.Text.ToStringEx().Trim()))
            {
                cmbEntityGeneratePath.Items.Insert(0, cmbEntityGeneratePath.Text.ToStringEx().Trim());
            }

            if (!cmbConnStr.Items.AsEnumerable<string>().Any(x => x == cmbConnStr.Text.ToStringEx().Trim()))
            {
                cmbConnStr.Items.Insert(0, cmbConnStr.Text.ToStringEx().Trim());
            }

            var json=new JObject()
            {
                ["Entity"]=new JObject(){
                    ["ConnStr"] = cmbConnStr.Items.AsEnumerable<object>().Select(x => x.ToStringEx()).ToArrayEx().ToJArray(),
                    ["DescFolder"] = cmbEntityGeneratePath.Items.AsEnumerable<object>().Select(x => x.ToStringEx()).ToArrayEx().ToJArray(),
                    ["LastNamespace"] = txtNamespace.Text.ToStringEx().Trim()
                },
                ["BLL"]=new JObject(){
                    ["BLLName"]= txtBllName.Text,
                    ["DescFolder"]= cmbBLLGeneratePath.Items.AsEnumerable<object>().Select(x => x.ToStringEx()).ToArrayEx().ToJArray(),
                    ["LastNamespace"] = txtBLLNamespace.Text
                }
                
            };

            File.WriteAllText("config.json",json.ToString(),Encoding.UTF8);
        }

        private void Generator_Load(object sender, EventArgs e)
        {
            dataGridView1.AutoGenerateColumns = false;
            if (File.Exists("config.json"))
            {
                loadConfigFromFile("config.json");
            }

            //cmbUsageType.SelectedIndex = 0;
            cmbFrameworkType.SelectedIndex = 1;

            dgvProc.AutoGenerateColumns = false;
            dgvBLLTable.AutoGenerateColumns = false;

            this.MaximumSize = new Size(this.Size.Width,this.Size.Height+30);
        }

        private void cmbDbList_SelectedIndexChanged(object sender, EventArgs e)
        {
            refreshStruct();
        }

        private bool connToDB(string connStr)
        {
            
            _builder = new SQLBuilder(connStr);

            cmbDbList.Items.Clear();

            try
            {
                _builder.Open();

                if (!cmbConnStr.Items.Contains(cmbConnStr.Text))
                {
                    cmbConnStr.Items.Insert(0, cmbConnStr.Text);

                    saveConfigToFile();
                }
            }
            catch (Exception exception)
            {
                
                return false;
            }

            var dblist = _builder.GetAllDb();

            cmbDbList.Items.AddRange(dblist);

            if (cmbDbList.Items.Count>0)
            {
                cmbDbList.SelectedIndex = 0;
            }
            
            return true;
        }

        private void cmbConnStr_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(cmbConnStr.Text))
            {
                MessageBox.Show("请先输入连接字符串");
                return;
            }


            if (!connToDB(cmbConnStr.Text))
            {
                MessageBox.Show("连接失败");
            }
        }

        private void btnBuild_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtDbContextName.Text))
            {
                MessageBox.Show("请输入DbContext名称");
                txtDbContextName.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txtNamespace.Text))
            {
                MessageBox.Show("请输入Namespace名称");
                txtNamespace.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(cmbEntityGeneratePath.Text))
            {
                MessageBox.Show("请选择文件输出目录");
                cmbEntityGeneratePath.Focus();
                return;
            }

            foreach (DbTableStructInfo table in ckTableList.CheckedItems)
            {
                var g=new SQLServerTableGenerator(table);

                g.Namespace = txtNamespace.Text.Trim();
                g.DbContextName = txtDbContextName.Text.Trim();

                var text = g.TransformText();

                writeToEntityFile(table.Name, text);

                setStatusText($"写入表:{table.Name}类完成");
            }



            saveConfigToFile();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtDbContextName.Text))
            {
                MessageBox.Show("请输入DbContext名称");
                txtDbContextName.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txtNamespace.Text))
            {
                MessageBox.Show("请输入Namespace名称");
                txtNamespace.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(cmbEntityGeneratePath.Text))
            {
                MessageBox.Show("请选择文件输出目录");
                cmbEntityGeneratePath.Focus();
                return;
            }

            var g=new SQLDbContextGenerator();
            g.Namespace = txtNamespace.Text.Trim();
            g.DbContextName = txtDbContextName.Text.Trim();
            g.TableNames = ckTableList.Items.AsEnumerable<DbTableStructInfo>().Select(x => x.Name)
                .ToArrayEx();
            var text = g.TransformText();

            writeToEntityFile(g.DbContextName, text);

            setStatusText("写入DbContext类完成");

            saveConfigToFile();
        }

        private void refreshStruct()
        {
            ckTableList.Items.Clear();
            dataGridView1.DataSource = new DbTableInfo_Column[0];

            var dbName = cmbDbList.SelectedItem.ToStringEx();

            lblStatus.Text = "正在加载数据库:" + dbName;
            this.Enabled = false;

            Task.Run(() =>
            {
                if (!string.IsNullOrWhiteSpace(dbName))
                {
                    //_builder.SetDb(cmbDbList.SelectedItem.ToStringEx());

                    var tbllst = _builder.GetTables(dbName);

                    var bllModules = tbllst.Where(x=>x.Type==0).Select(x => new TableModuleInfo()
                    {
                        Checked=true,
                        TableName=x.Name,
                        BLLManager=T4SQLHelper.FirstLetterUpper(T4SQLHelper.GetModuleName(x.Name))+"Manager",
                        Comment=x.Comment,
                        Table = x
                    }).ToArrayEx();

                    var procList=_builder.GetProcs(dbName);

                    this.Invoke(new MethodInvoker(() =>
                    {
                        ckTableList.Items.AddRange(tbllst);

                        dgvProc.DataSource = procList;
                        dgvBLLTable.DataSource = bllModules;

                        this.Enabled = true;
                        
                        btnBuildProc.Enabled = procList.Length > 0;

                        txtDbContextName.Text = $"{dbName}Context";

                        lblStatus.Text = "数据库:" + dbName + "加载完成";
                    }));
                }
            });
        }
        

        private void writeToEntityFile(string fileName,string content)
        {
            if (!Directory.Exists(cmbEntityGeneratePath.Text))
            {
                Directory.CreateDirectory(cmbEntityGeneratePath.Text);
            }

            var filePath = Path.Combine(cmbEntityGeneratePath.Text, fileName.Trim() + ".cs");
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            File.WriteAllText(filePath, content,Encoding.UTF8);
            
        }

        private void setStatusText(string text)
        {
            lblStatus.Text = text;
        }

        private void chkSelectAllTable_CheckedChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < ckTableList.Items.Count; i++)
            {
                ckTableList.SetItemChecked(i, chkSelectAllTable.Checked);
            }
        }

        private void btnBuildProc_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtDbContextName.Text))
            {
                MessageBox.Show("请输入DbContext名称");
                txtDbContextName.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txtNamespace.Text))
            {
                MessageBox.Show("请输入Namespace名称");
                txtNamespace.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(cmbEntityGeneratePath.Text))
            {
                MessageBox.Show("请选择文件输出目录");
                cmbEntityGeneratePath.Focus();
                return;
            }

            var g = new SQLServerProcGenerator();
            g.Namespace = txtNamespace.Text.Trim();
            g.DbContextName = txtDbContextName.Text.Trim();
            g.ProcList = (DbProcInfo[])dgvProc.DataSource;
            
            var text = g.TransformText();

            writeToEntityFile(g.DbContextName + ".proc", text);

            setStatusText("写入存储过程类完成");

            saveConfigToFile();
        }



        private void btnBuildBLL_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(cmbBLLGeneratePath.Text))
            {
                MessageBox.Show("生成路径不能为空");
                return;
            }

            if (string.IsNullOrWhiteSpace(txtBLLNamespace.Text))
            {
                MessageBox.Show("命名空间不能为空");
                return;
            }

            saveConfigToFile();

            if (cbkBaseManager.Checked)
            {
                var template=new BLLBaseManagerGenerator();
                template.ContextName = txtDbContextName.Text.Trim();
                template.Namespace = txtBLLNamespace.Text.Trim();

                template.IsNetCore = cmbFrameworkType.SelectedIndex==1;
                var code=template.TransformText();

                writeToBLLFile("BaseManager",code);
            }

            var dt = (TableModuleInfo[]) dgvBLLTable.DataSource;

            if (!dt.Any(x=>x.Checked))
            {
                MessageBox.Show("选择要生成Manager的表");
                return;
            }

            dt = dt.Where(x => x.Checked).ToArrayEx();

            foreach (var info in dt.Where(x=>x.Checked))
            {
                var template = new BLLManagerGenerator();
                template.IsAsyncEnabled = cbkBuildAsync.Checked;
                template.IsSyncEnabled = cbkBuildSync.Checked;

                template.IsBuildAdd = ckbAddMethod.Checked;
                template.IsBuildDelete = ckbBuildDelte.Checked;
                template.IsBuildExists = cbkExistsMethod.Checked;
                template.IsBuildGet = ckbGetMethod.Checked;
                template.IsBuildSetState = cbkSetStateMethod.Checked;
                template.IsBuildUpdate = cbkUpdateMethod.Checked;

                template.Namespace = txtBLLNamespace.Text;
                template.Table = info.Table;
                template.ModuleName = T4SQLHelper.GetModuleName(info.TableName);
                template.ModuleBLLName = info.BLLManager;

                var code = template.TransformText();

                writeToBLLFile(info.BLLManager,code);
            }
        }

        private void btnBLLPathFinder_Click(object sender, EventArgs e)
        {
            getFolderPath(cmbBLLGeneratePath);
        }

        private void writeToBLLFile(string fileName, string content)
        {
            if (!Directory.Exists(cmbBLLGeneratePath.Text))
            {
                Directory.CreateDirectory(cmbBLLGeneratePath.Text);
            }

            var filePath = Path.Combine(cmbBLLGeneratePath.Text, fileName.Trim() + ".cs");
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            File.WriteAllText(filePath, content, Encoding.UTF8);

        }

        private void writeWebFile(int type, string fileName, string content)
        {
            if (!Directory.Exists(cmbBuildWebPath.Text))
            {
                Directory.CreateDirectory(cmbBuildWebPath.Text);
            }

            var filePath = Path.Combine(cmbBLLGeneratePath.Text,type.Switch("").Case(0,"Views").Case(1,"Models").Case(2,"Controllers"), fileName.Trim());
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            File.WriteAllText(filePath,content);
        }

        private string getFolderPath(ComboBox cmb)
        {
            folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
            folderBrowserDialog1.SelectedPath = cmb.Text;

            folderBrowserDialog1.ShowNewFolderButton = true;
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                cmb.Text = folderBrowserDialog1.SelectedPath;

                if (!cmbEntityGeneratePath.Items.Contains(folderBrowserDialog1.SelectedPath))
                {
                    cmb.Items.Insert(0, folderBrowserDialog1.SelectedPath);

                    saveConfigToFile();
                }

                return folderBrowserDialog1.SelectedPath;
            }
            
            return "";
        }

        private void cbkSelectAllMethod_CheckedChanged(object sender, EventArgs e)
        {
            ckbAddMethod.Checked=cbkSelectAllMethod.Checked;
            ckbBuildDelte.Checked = cbkSelectAllMethod.Checked;
            cbkExistsMethod.Checked = cbkSelectAllMethod.Checked;
            ckbGetMethod.Checked = cbkSelectAllMethod.Checked;
            cbkSetStateMethod.Checked = cbkSelectAllMethod.Checked;
            cbkUpdateMethod.Checked = cbkSelectAllMethod.Checked;
        }
        
        private void btnBuildWebPath_Click(object sender, EventArgs e)
        {
            getFolderPath(cmbBuildWebPath);
        }

        private void btnBuildWeb_Click(object sender, EventArgs e)
        {
            foreach (DbTableStructInfo item in ckWebTables.SelectedItems)
            {
                var moduleName = T4SQLHelper.GetModuleName(item.Name);

                if (cbkBuildWebController.Checked)
                {
                    var t = new ControllerGenerator()
                    {
                        ModuleName = moduleName,
                        Namespace = txtBuildWebNamespace.Text + "Controllers",
                        Table = item
                    };

                    var code = t.TransformText();

                    writeWebFile(2,t.ModuleName +".cs",code);
                }

                if (cbkBuildWebListView.Checked)
                {
                    var t=new ListViewGenerator();

                    t.Session=new Dictionary<string, object>()
                    {
                        ["ModuleName"] = moduleName,
                        ["Namespace"] = txtBuildWebNamespace.Text + "Controllers",
                        ["Table"] = item
                    };

                    var code = t.TransformText();

                    writeWebFile(0,$"{moduleName}/List.cshtml",code);
                }

                if (cbkBuildWebDetailView.Checked)
                {
                    var t = new DetailViewGenerator();

                    t.Session = new Dictionary<string, object>()
                    {
                        ["ModuleName"] = moduleName,
                        ["Namespace"] = txtBuildWebNamespace.Text + "Controllers",
                        ["Table"] = item
                    };

                    var code = t.TransformText();

                    writeWebFile(0, $"{moduleName}/Detail.cshtml", code);
                }

                if (cbkBuildWebListView.Checked || cbkBuildWebListView.Checked)
                {
                    var t = new ViewModelGenerator();

                    t.Session = new Dictionary<string, object>()
                    {
                        ["ModuleName"] = moduleName,
                        ["Namespace"] = txtBuildWebNamespace.Text + "Controllers",
                        ["Table"] = item
                    };

                    var code = t.TransformText();

                    writeWebFile(1, $"{moduleName}/Model_{moduleName}.cs", code);
                }
            }

            
        }
    }

    public class TableModuleInfo
    {
        public bool Checked { set; get; }

        public string TableName { set; get; }

        public string BLLManager { set; get; }

        public string Comment { set; get; }

        public DbTableStructInfo Table { set; get; }
    }
}
